package com.faya.green.utils;

import com.faya.green.model.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;

import java.util.List;

/**
 * @author ：LX
 * 创建时间： 2018/11/3. 23:27
 * 地点：广州
 * 目的: shrio 权限相关的工具类
 *      （这里的方法并不会去使用，主要是为了做笔记，shiro已经对权限的方法封装的很好了，直接调用即可）
 * 备注说明：
 */
public class ShiroUtils {


    /**
     * 用户登录
     * @param subject Subject实例
     * @param token token令牌，记录用户认证的身份和凭证即账号和密码
     */
    public static void login(Subject subject, UsernamePasswordToken token){
        subject.login(token);
    }

    /**
     * 获得 Subject实例，表示一个用户
     * @return
     */
    public static Subject createSubject(){
        return SecurityUtils.getSubject();
    }

    /**
     * 获取用户认证状态
     * @param subject Subject实例，表示一个用户
     * @return
     */
    public static boolean isAuthenticated(Subject subject){
        boolean authenticated = subject.isAuthenticated();
        return authenticated;
    }

    /**
     * 用户退出
     * @param subject Subject实例，一个用户
     */
    public static void exitUser(Subject subject){
        subject.logout();
    }

    /**
     * MD5不加盐的 加密
     * @param str 待加密字符串
     * @return
     */
    public static String md5Encryption(String str){
        return new Md5Hash(str).toString();
    }

    /**
     * MD5 加密
     * @param str 待加密字符串
     * @param sale 盐
     * @param num 加密几次（散列次数）,多次加密相当于md5(md5())
     * @return
     */
    public static String md5EncryptionSale(String str, String sale, int num){
        if (num == 0){
            num = 1;
        }
        return new Md5Hash(str, sale, num).toString();
    }

    /**
     * 判断是否 该角色
     * @param role 角色，判断是不是这个角色
     * @param subject Subject实例，一个用户
     * @return true 是这个角色， false 不是这个角色
     */
    public static boolean isRole(String role, Subject subject){
        return subject.hasRole(role);
    }

    /**
     * 判断用户是否拥有多个角色
     * @param role 角色的集合
     * @param subject Subject实例，一个用户
     * @return true 有， false 不拥有
     */
    public static boolean isRoles(List<String> role, Subject subject){
        return subject.hasAllRoles(role);
    }

    /**
     * 判断用户是否拥有这个权限
     * @param author 要判断的权限  user:delete
     * @param subject Subject实例，一个用户
     * @return true 有， false 不拥有
     */
    public static boolean isPermitted(String author, Subject subject){
        return subject.isPermitted(author);
    }

    /**
     * 判断用户是否拥有这些权限
     * @param author 要判断的权限 "user:create:1", "user:delete"
     * @param subject Subject实例，一个用户
     * @return true 有， false 不拥有
     */
    public static boolean isPermittedAll(String author, Subject subject){
        return subject.isPermittedAll(author);
    }

    /**
     * 检查权限，失败抛出异常 UnauthorizedException
     * @param author 权限  sys:user:delete
     * @param subject Subject实例，一个用户
     */
    public static void checkPermission (String author, Subject subject){
        subject.checkPermission(author);
    }

    /**
     * 检查是否拥有多个权限，失败抛出异常 UnauthorizedException
     * @param author 权限 user:create:1","user:delete
     * @param subject Subject实例，一个用户
     */
    public static void checkPermissions(String author, Subject subject){
        subject.checkPermissions(author);
    }

    /**
     * 检查角色，失败抛出异常 UnauthorizedException
     * @param role 角色  role1
     * @param subject Subject实例，一个用户
     */
    public static void checkRole(String role, Subject subject){
        subject.checkRole(role);
    }

    /**
     * 检查是否拥有多个角色，失败抛出异常 UnauthorizedException
     * @param roles 角色 "role1", "role2" 字符串或 Arrays.asList("role1", "role2")
     * @param subject Subject实例，一个用户
     */
    public static void checkRoles(String roles, Subject subject){
        subject.checkRoles(roles);
    }

    /**
     * 获取用户
     * @param subject Subject实例，一个用户
     * @return
     */
    public static User getPrincipal(Subject subject){
        //注意，这里的User根据放入进去的model来变化的，比如其他的系统usermodel来存放用户，那就是这个来强转
        return (User)subject.getPrincipal();
    }

    /**
     * 从token中获取用户名
     * @param token
     * @return
     */
    public static String getUserName(AuthenticationToken token){
        String userName = (String)token.getPrincipal();
        return userName;
    }

    /**
     * 网上找的一个清除 缓存的方法，未验证，解决赋权后不生效的问题
     * @param subject Subject实例，一个用户
     */
    public static void clear(Subject subject){
        RealmSecurityManager securityManager = (RealmSecurityManager) SecurityUtils.getSecurityManager();
        JdbcRealm jdbcRealm = (JdbcRealm)securityManager.getRealms().iterator().next();
        //删除登陆人
        jdbcRealm.getAuthorizationCache().remove(subject.getPrincipal());
        //删除登陆人对应的缓存
        jdbcRealm.getAuthorizationCache().remove(subject.getPrincipals());
        //重新加载subject
        subject.releaseRunAs();
    }
}
